#include <SPI.h>

#include <Wire.h>

#include <ETH.h>
#include <WiFi.h>
#include <WiFiAP.h>
#include <WiFiClient.h>
#include <WiFiGeneric.h>
#include <WiFiMulti.h>
#include <WiFiProv.h>
#include <WiFiScan.h>
#include <WiFiServer.h>
#include <WiFiSTA.h>
#include <WiFiType.h>
#include <WiFiUdp.h>




#include <WiFi.h>
#include <time.h>
#include <RDA5807.h>
#include <SPI.h>
#include <U8g2lib.h>
#include <Ticker.h>

const char* ssid     = "iron2222";      //网络名称
const char* password = "18436099009";      //网络密码

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600*7;    //时区
const int   daylightOffset_sec = 3600; //夏令时

String wificonnect(){
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid,password);
  while(WiFi.status() != WL_CONNECTED){ //未连接上
    delay(400);
  }
  return WiFi.localIP().toString(); //连接上
}

int KEY1 = 1; //按键定义
int KEY2 = 2;
int KEY3 = 3;
int KEY4 = 6;

//选择输出设备
//0：时间显示 1:FM收音机 2:网络电台
uint8_t modelsign = 0; //默认为无输出
void selectDevice(uint8_t dev) {
  if(dev == 1) {
    digitalWrite(41, LOW);
    digitalWrite(42, LOW);
  }
  if(dev == 1) {
    digitalWrite(41, HIGH);
    digitalWrite(42, LOW);
  }
  if(dev == 2) {
    digitalWrite(41, HIGH);
    digitalWrite(42, HIGH);
  }
}

#define ESP32_I2C_SDA 5
#define ESP32_I2C_SCL 4

#define MAX_DELAY_RDS 40
#define MAX_STATIONS 10

long rds_elapsed = millis();
uint8_t volume = 1; //初始化音量
RDA5807 rx;

uint8_t stations = 0;     //当前选中的电台
uint16_t fmstation[MAX_STATIONS] = {0};   //最多允许电台

//搜索收音机的台
//8700~10800MZH
void searchFM() {
  uint16_t i = 0;
  uint8_t num = 0;
  rx.setFrequency(8700); //从8700MHZ开始扫描
  while(i < 210) {
    delay(100);
    if(rx.isStereo() && rx.getRssi() > 35) {
      fmstation[num++] = findMaxSing(rx.getFrequency(), rx.getRssi());
      if (num >= MAX_STATIONS)
        return;
    }
    rx.setFrequencyUp();
    i++;
  }
  for(i = 0; i < MAX_STATIONS; i++) {
    Serial.print("FMRadio");
    Serial.print(fmstation[i]);
    Serial.print(rx.getFrequency());
  }
  Serial.println("Search over!");
}

uint16_t findMaxSing(uint16_t freq, uint8_t rssi) {
  while(rx.isStereo()) {
    rx.setFrequencyUp();
    delay(100);
    if(rx.isStereo() && rx.getRssi() > rssi) {
      freq = rx.getFrequency();
      rssi = rx.getRssi();
    }
  }
  return freq;
}

//收音机换台
void changestation() {
  while (1) {
    if (stations == MAX_STATIONS - 1) {
      stations = 0;
      rx.setFrequency(fmstation[stations]);
      //Serial.println(fmstation[stations]);
      return;
    }
    if (fmstation[stations + 1] != 0) {
      rx.setFrequency(fmstation[stations + 1]);
      stations++;
      Serial.println(fmstation[stations]);
      return;
    }
    stations++;
  }
}

//当前可用电台
uint8_t countStation() {
  uint8_t i;
  for(i = 0; i < MAX_STATIONS; i++) {
    if(fmstation[i] == 0)
      return i;
  }
  return i;
}

U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(/*显示方向*/U8G2_R0, /*clock/SCL*/ 36, /*data/SDA*/ 35, /*cs=*/ 46, /*DC=*/ 33, /*reset/RST*/ 34);

//时间控制
int oldsec = -1;     //上次显示时的秒
String ipaddress;    //本机的IP地址

//网络播放控制部分
uint8_t netbuf[3][1024];      //网络数据缓冲区
uint16_t writep = 0;          //写入数量
uint16_t readp = 0;           //读取数量
WiFiClient client;
bool connstat = false;        //连接状态
bool iswaitecho = false;      //是否等待服务器回应
Ticker flipper;               //时间中断
uint16_t m_offset = 0;

#define WEBSERVERIP "192.168.43.172"
#define WEBSERVERPORT 8888

void onTimer(void) {
  if(readp<=writep)  dacWrite(17, netbuf[readp % 3][m_offset++]);      //播放一次声音
  if (m_offset >= 1024) {
    m_offset = 0;
    readp++;      //读取完成一个缓冲区
  }
}

//连接网络音乐服务器
bool connNetMusic() {
  uint8_t i = 0;
  while (i < 5) { //最多连接5次
    if (client.connect(WEBSERVERIP, WEBSERVERPORT)) {
      connstat = true;
      Serial.println("连接成功");
      return true;
    } else {
      Serial.println("访问失败");
      client.stop(); //关闭客户端
    }
    i++;
    delay(100);
  }
  return false;
}

void dispSerCustStat() {
  Serial.print("Sour=");
  Serial.print(modelsign);
  Serial.print("    Station=");
  Serial.print(stations);
  Serial.print(" vol=");
  Serial.println(volume);
}

void dispwelcome() {
  u8g2.firstPage();
  u8g2.clearBuffer();         //清除内部缓冲区
  u8g2.setFontDirection(0);   //设置字体方向
  u8g2.setFont(u8g2_font_ncenB14_tr);     //设置字体
  u8g2.setCursor(10, 35);
  u8g2.print("Loading-");
  u8g2.sendBuffer();
}

void dispOled() {
  struct tm timeinfo;
  char str[64] = {0};
  if(!getLocalTime(&timeinfo)) {
    Serial.println("Failed to obtain time");
    return;
  }
  if(oldsec == timeinfo.tm_sec)
    return;
  oldsec = timeinfo.tm_sec;

  if(modelsign == 0) {
    u8g2.clearBuffer();
    u8g2.setFontDirection(0);
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.setCursor(20, 15);
    u8g2.print(&timeinfo, "%H:%M:%S");
    u8g2.setCursor(15, 35);
    u8g2.print(&timeinfo, "%Y/%m/%d");
    u8g2.setCursor(2,55);
    u8g2.print(ipaddress.c_str());
  }
  else if(modelsign == 1) {
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_ncenB12_tr);
    u8g2.setCursor(30, 20);
    sprintf(str, "FM:%d/%d", stations + 1, countStation());
    u8g2.print(str);
    u8g2.setCursor(25, 40);
    sprintf(str, "Vol:%02d/%d", volume, 15);
    u8g2.print(str);
    u8g2.setCursor(20,60);
    
    sprintf(str, "Freq: %d MHz", fmstation[stations]);
    u8g2.print(str);
  }
  else if(modelsign == 2) {
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_ncenB14_tf);
    if (connstat == false) {
      u8g2.setCursor(20, 20);
      u8g2.print("NetRadio");
      u8g2.setCursor(2, 40);
      u8g2.setFont(u8g2_font_ncenB10_tf);
      u8g2.print("Connection failed.");
    } else {
      u8g2.setCursor(20, 20);
      u8g2.print("NetRadio");
      u8g2.setCursor(2, 40);
      u8g2.setFont(u8g2_font_ncenB10_tf);
      sprintf(str, "%s:%d", WEBSERVERIP, WEBSERVERPORT);
      u8g2.print(str);
    }
  }
  u8g2.sendBuffer();
}

//显示当前音源选择信息
void dispMusicSour() {
  u8g2.setFont(u8g2_font_ncenB12_tr);     //设置字体
  u8g2.setCursor(0, 40);
  if(modelsign == 0) {
    u8g2.print("MUTE");
  }
  u8g2.sendBuffer();
}

void setup() {
  Serial.begin(115200); //初始化串口
  u8g2.begin(); //显示器初始化
  dispwelcome();    //显示欢迎画面
  pinMode(41, OUTPUT);
  pinMode(42, OUTPUT);
  // The line below may be necessary to setup I2C pins on ESP32
  //收音机
  Wire.begin(ESP32_I2C_SDA, ESP32_I2C_SCL);
  rx.setup();
  rx.setVolume(volume);
  searchFM();
  rx.setFrequency(fmstation[stations]);
  selectDevice(modelsign);
  ipaddress = wificonnect();
  Serial.println(ipaddress.c_str());

  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

  pinMode(KEY1, INPUT_PULLUP); //上拉输入
  pinMode(KEY2, INPUT_PULLUP);
  pinMode(KEY3, INPUT_PULLUP);
  pinMode(KEY4, INPUT_PULLUP);

}
void loop() {
  uint16_t num=0;
  //循环监听
  //按键1:模式切换 按键2：频道切换 按键3：音量降低 按键4：音量提高
  if(digitalRead(KEY1) == LOW) { //按键被按下
    delay(100); //消除抖动
    if(digitalRead(KEY1) == LOW) { //确认按键被按下
      if (modelsign == 2) { //由网络音乐 转换到其他状态   需要关闭网络
        client.write('q');
        client.stop(); //关闭客户端
        flipper.detach();
        connstat = false;
      }
      if(modelsign == 2)
        modelsign == 0;
      else
        modelsign++;
      selectDevice(modelsign);
      if (modelsign == 2) { //变为网络音乐  需要连接网络
        connNetMusic();
      }
      oldsec = -1;
      dispSerCustStat();
    }
  }
  //网络音乐连接后 需要从网络上获取数据
  if (modelsign == 2 && connstat == true) {
    if (iswaitecho == false && (writep - readp) < 2) {
      client.write('n');
      iswaitecho = true;
    }
    if(writep%120==0) dispOled();
    if (client.available()) {
      num = client.read(netbuf[writep % 3], 1024);
      if (writep == 0 && readp == 0) {
        flipper.attach(0, onTimer);
      }
      writep++;
      iswaitecho = false;
    }
  }
  else{
    //一旦网络连接开始播放音乐，
    dispOled();
  }

  if (modelsign == 1) {
    if (digitalRead(KEY2) == LOW) { // 若按键2被按下  换台
      delay(100); //等待跳过按键抖动的不稳定过程
      if (digitalRead(KEY2) == LOW) { // 若按键被按下
        //换台
        changestation();
        dispSerCustStat();
        oldsec = -1;
      }
    }

    if (digitalRead(KEY3) == LOW) {
      delay(100);
      if (digitalRead(KEY3) == LOW) {
        if (volume > 0)
          volume--;
        rx.setVolume(volume);
        dispSerCustStat();
        oldsec = -1;
      }
    }

    if (digitalRead(KEY4) == LOW) {
      delay(100);
      if (digitalRead(KEY4) == LOW) {
        if(volume < 15)
          volume++;
        rx.setVolume(volume);
        dispSerCustStat();
        oldsec = -1;
      }
    }
  }
}
